package org.lc.stk.service.baseInfo.impl;

import java.util.List;
import java.util.Optional;

import org.lc.stk.dao.baseInfo.DepartmentRepository;
import org.lc.stk.dao.baseInfo.DepartmentTypeRepository;
import org.lc.stk.model.baseInfo.Department;
import org.lc.stk.model.baseInfo.DepartmentType;
import org.lc.stk.service.baseInfo.DepartmentService;
import org.lc.stk.service.exception.BusinessException;
import org.lc.stk.service.support.QuerySpecifications;
import org.lc.stk.web.dto.department.CreateDepartmentRequest;
import org.lc.stk.web.dto.department.DepartmentQuery;
import org.lc.stk.web.dto.department.UpdateDepartmentRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

@Service
@Transactional
public class DepartmentServiceImpl implements DepartmentService {

    @Autowired
    private DepartmentRepository departmentRepository;

    @Autowired
    private DepartmentTypeRepository departmentTypeRepository;

    @Override
    public Department create(CreateDepartmentRequest request) {
        // 检查编码唯一性
        if (departmentRepository.findByCode(request.getCode()).isPresent()) {
            throw new BusinessException("部门编码已存在");
        }

        // 检查名称唯一性
        if (departmentRepository.findByName(request.getName()).isPresent()) {
            throw new BusinessException("部门名称已存在");
        }

        Department department = new Department();
        department.setName(request.getName());
        department.setCode(request.getCode());
        department.setOrderNum(request.getOrderNum());
        department.setRemark(request.getRemark());

        // 设置部门类型
        if (request.getTypeId() != null) {
            DepartmentType type = departmentTypeRepository.findById(request.getTypeId())
                .orElseThrow(() -> new BusinessException("部门类型不存在"));
            department.setType(type);
        }

        // 设置上级部门
        if (request.getParentId() != null) {
            Department parent = departmentRepository.findById(request.getParentId())
                .orElseThrow(() -> new BusinessException("上级部门不存在"));
            department.setParent(parent);
        }

        return departmentRepository.save(department);
    }

    @Override
    public Department update(UpdateDepartmentRequest request) {
        Department department = getById(request.getId());

        // 检查编码唯一性
        if (StringUtils.hasText(request.getCode()) 
            && !request.getCode().equals(department.getCode())
            && departmentRepository.findByCode(request.getCode()).isPresent()) {
            throw new BusinessException("部门编码已存在");
        }

        // 检查名称唯一性
        if (StringUtils.hasText(request.getName()) 
            && !request.getName().equals(department.getName())
            && departmentRepository.findByName(request.getName()).isPresent()) {
            throw new BusinessException("部门名称已存在");
        }

        if (StringUtils.hasText(request.getName())) {
            department.setName(request.getName());
        }
        if (StringUtils.hasText(request.getCode())) {
            department.setCode(request.getCode());
        }
        if (request.getOrderNum() != null) {
            department.setOrderNum(request.getOrderNum());
        }
        if (StringUtils.hasText(request.getRemark())) {
            department.setRemark(request.getRemark());
        }

        // 更新部门类型
        if (request.getTypeId() != null) {
            DepartmentType type = departmentTypeRepository.findById(request.getTypeId())
                .orElseThrow(() -> new BusinessException("部门类型不存在"));
            department.setType(type);
        }

        // 更新上级部门
        if (request.getParentId() != null) {
            if (!request.getParentId().equals(department.getParent() == null ? null : department.getParent().getId())) {
                Department parent = getById(request.getParentId());
                department.setParent(parent);
            }
        } else {
            department.setParent(null);
        }

        return departmentRepository.save(department);
    }

    @Override
    public void delete(Integer id) {
        Department department = getById(id);
        department.setIsDeleted(true);
        departmentRepository.save(department);
    }

    @Override
    public Department getById(Integer id) {
        return departmentRepository.findById(id)
                .orElseThrow(() -> new BusinessException("部门不存在"));
    }

    @Override
    public List<Department> getAll() {
        return departmentRepository.findAllActive();
    }

    @Override
    public List<Department> getTree() {
        List<Department> rootDepartments = departmentRepository.findByParentIsNull();
        return buildDepartmentTree(rootDepartments);
    }

    private List<Department> buildDepartmentTree(List<Department> parentDepartments) {
        parentDepartments.forEach(department -> {
            List<Department> children = departmentRepository.findByParent(department);
            department.setChildren(children);
            if (!children.isEmpty()) {
                buildDepartmentTree(children);
            }
        });
        return parentDepartments;
    }

    @Override
    public List<Department> getByParentId(Integer parentId) {
        if (parentId == null) {
            return departmentRepository.findByParentIsNull();
        }
        return departmentRepository.findByParentId(parentId);
    }

    @Override
    public boolean isNameExists(String name, Integer excludeId) {
        Optional<Department> department = departmentRepository.findByName(name);
        return department.isPresent() && !department.get().getId().equals(excludeId);
    }

    @Override
    public boolean isCodeExists(String code, Integer excludeId) {
        Optional<Department> department = departmentRepository.findByCode(code);
        return department.isPresent() && !department.get().getId().equals(excludeId);
    }

    @Override
    public Page<Department> query(DepartmentQuery query, Pageable pageable) {
        Specification<Department> spec = buildSpecification(query);
        return departmentRepository.findAll(spec, pageable);
    }

    private Specification<Department> buildSpecification(DepartmentQuery query) {
        Specification<Department> spec = Specification.where(
            QuerySpecifications.equal("isDeleted", false)
        );

        if (StringUtils.hasText(query.getName())) {
            spec = spec.and(QuerySpecifications.like("name", query.getName()));
        }
        if (StringUtils.hasText(query.getCode())) {
            spec = spec.and(QuerySpecifications.like("code", query.getCode()));
        }
        if (query.getTypeId() != null) {
            spec = spec.and(QuerySpecifications.equal("type.id", query.getTypeId()));
        }
        if (query.getParentId() != null) {
            spec = spec.and(QuerySpecifications.equal("parent.id", query.getParentId()));
        }

        return spec;
    }
}